package io.jnet.client.clientchannelcontext;

import java.io.IOException;
import java.nio.channels.AsynchronousSocketChannel;
import com.jfireframework.baseutil.collection.buffer.ByteBuf;
import com.jfireframework.baseutil.collection.buffer.DirectByteBuf;
import com.jfireframework.baseutil.resource.ResourceCloseAgent;
import com.jfireframework.baseutil.resource.ResourceCloseCallback;
import io.jnet.client.api.ClientChannelContext;
import io.jnet.client.api.ClientListener;
import io.jnet.client.api.ReadHandler;
import io.jnet.client.api.WriteHandler;
import io.jnet.client.read.SimpleReadHandler;
import io.jnet.client.write.SimpleWriteHandler;
import io.jnet.common.bufstorage.BufStorage;
import io.jnet.common.decodec.FrameDecodec;
import io.jnet.common.streamprocessor.StreamProcessor;
import io.jnet.common.util.ProcesserUtil;

public class SimpleClientChannelContext implements ClientChannelContext
{
    
    private final ByteBuf<?>                               ioBuf;
    private final AsynchronousSocketChannel                socketChannel;
    private final ResourceCloseAgent<ClientChannelContext> closeAgent = new ResourceCloseAgent<ClientChannelContext>(this, new ResourceCloseCallback<ClientChannelContext>() {
                                                                          
                                                                          @Override
                                                                          public void onClose(ClientChannelContext resource)
                                                                          {
                                                                              try
                                                                              {
                                                                                  socketChannel.close();
                                                                              }
                                                                              catch (IOException e)
                                                                              {
                                                                                  e.printStackTrace();
                                                                              }
                                                                              finally
                                                                              {
                                                                                  ioBuf.release();
                                                                              }
                                                                          }
                                                                      });
    private final ReadHandler                              readHandler;
    private final WriteHandler                             writeHandler;
    private final StreamProcessor[]                        outProcessors;
    private final BufStorage                               bufStorage;
    
    public SimpleClientChannelContext(//
            int maxMerge, //
            BufStorage bufStorage, //
            StreamProcessor[] outProcessors, //
            AsynchronousSocketChannel socketChannel, //
            ClientListener clientListener, //
            StreamProcessor[] inProcessors, //
            FrameDecodec frameDecodec)
    {
        this.bufStorage = bufStorage;
        this.outProcessors = outProcessors;
        this.socketChannel = socketChannel;
        ioBuf = DirectByteBuf.allocate(128);
        readHandler = new SimpleReadHandler(clientListener, this, inProcessors, ioBuf, frameDecodec, socketChannel);
        writeHandler = new SimpleWriteHandler(maxMerge, socketChannel, clientListener, bufStorage, this);
    }
    
    @Override
    public boolean close()
    {
        return closeAgent.close();
    }
    
    @Override
    public boolean isOpen()
    {
        return socketChannel.isOpen();
    }
    
    @Override
    public void registerRead()
    {
        readHandler.registerRead();
    }
    
    @Override
    public void write(Object send, int index) throws Throwable
    {
        send = ProcesserUtil.process(this, outProcessors, send, index);
        if (send instanceof ByteBuf<?>)
        {
            bufStorage.putBuf((ByteBuf<?>) send);
            writeHandler.commitWrite();
        }
    }
    
}
